
\chapter{Plataforma base de desenvolvimento}
\label{c:plataforma_base}

O primeiro passo na construção de uma plataforma de desenvolvimento de software
completa para uma dada arquitetura nova é o desenvolvimento de uma camada
básica que possibilite a construção de software em linguagem de montagem. A
programação neste nível, comumente denominado de ``baixo nível'', apresenta
vantagens e desvantagens, considerações que já foram discutidas no capítulo
\ref{c:sistemas_embarcados}. Como vimos, um programa escrito manualmente em
baixo nível tem a liberdade de poder aplicar otimizações de eficiência ou
diminuir o tamanho do executável usando truques que são difíceis de serem
empregados por um compilador, porém estão ao alcance de um profissional com
experiência na área e um conhecimento profundo da arquitetura.

Mesmo que não seja o caso de desenvolver tal software em baixo nível, todo o
desenvolvimento de software em alto nível, como o presente em sistemas
embarcados em geral, tem um passo de compilação onde o código é traduzido da
linguagem original e o resultado da tradução passa a utilizar as instruções que
a arquitetura base provê, preservando a semântica do programa original. A
plataforma base de desenvolvimento é o pilar responsável pela execução de todo
o software para o RISCO.

Entretanto, a geração do código binário executável não é o objetivo final da
plataforma base. O desenvolvedor necessita, de algum modo, executar este
programa e observar o seu comportamento, a fim de realizar modificações em
geral no código original, corrigindo-o. Ainda mais, é necessário que ele
possa executar o código a partir de uma máquina que não utiliza o processador
RISCO, obtendo os mesmos efeitos que seriam obtidos caso ela o utilizasse. 

As ferramentas \texttt{risco-as} e \texttt{risco-sim} compõem a plataforma base
de desenvolvimento de software em linguagem de montagem para o processador
RISCO, atendendo às necessidades delineadas acima. Nas seções a seguir tem-se
uma exposição destas ferramentas, as suas motivações, decisões de projeto e
funcionalidades.


\section{Montador}

O montador é o software responsável pela tradução de um código fonte escrito em
linguagem de montagem, utilizando instruções do processador alvo, para um
arquivo binário contendo instruções, codificadas de acordo com as regras do
alvo, e dados, que serão utilizados pelas instruções. De acordo com a definição
dada, ele é de fato um compilador. Entretanto, não é comum utilizar essa
denominação pois existem algumas diferenças entre as características de um
montador e de um compilador tradicional:

\begin{itemize}
  \item Em geral, a linguagem fonte e a linguagem destino de um montador são
  quase idênticas, diferindo somente em detalhes, como será visto adiante.
  
  \item A linguagem fonte não apresenta diversos tipos de dados ou construções,
  nem meios de composição de tipos. Ela é suficientemente simples para ser uma
  representação fiel do conjunto de instruções do processador.
  
  \item Como a linguagem de montagem é bastante simples, sem uma grande
  quantidade de construções sintáticas, como uma linguagem de alto nível, o 
  processo de tradução é mais mecânico. Não são necessárias diversas análises no
  código, ou passes de otimização.
\end{itemize}

A interação entre o compilador e o montador aborda diversos aspectos
interessantes, fazendo com que o projetista deva balancear o conjunto de todas
as funcionalidades requisitadas entre os dois. Como será visto na seção
\ref{ss:assembly_risco}, a linguagem de montagem está em um nível de
abstração um pouco acima do conjunto de instruções do compilador. As
facilidades que ela apresenta simplifica consideravelmente a implementação do
compilador. Porém há um limite, pois quanto mais funcionalidade depender do
montador, mais sua complexidade irá aumentar. No outro extremo, existe a opção
de se livrar do montador como um todo e fazer com que o próprio compilador gere
o código binário executável \cite{llvm_mc}. Isto elimina o passo intermediário
de geração do arquivo de texto que seria passado para o montador, aumentando a
eficiência do processo como um todo. A maior desvantagem seria o aumento de
complexidade no compilador, que teria de lidar com todas as tarefas do
assembler.

A ferramenta \textbf{risco-as}, o montador construído para a plataforma RISCO,
apresenta algumas decisões de projeto que diferem da norma apresentada acima e
do fluxograma da figura \ref{fig:fluxo_desenvolvimento}. A diferença é que a
funcionalidade de ligador foi incluída nesse programa. Desse modo, ele recebe
como entrada um conjunto de arquivos em linguagem de montagem e gera o arquivo
executável final, sem precisar realizar o passo de ligação com um programa
externo. A desvantagem mais significativa desta decisão é que ele não consegue
unir um programa sendo escrito em linguagem de montagem com uma biblioteca
pré-compilada, disponível em código binário. Na prática, isto não prejudica o
processo de desenvolvimento como um todo, pois ainda é possível utilizar a
biblioteca caso o seu código fonte esteja disponível. Entretanto, perde-se o
modelo de compilação separada, e o tempo médio de compilação aumenta.

O papel principal do montador, em termos de funcionalidade, é facilitar a
geração de código do compilador tomando conta das tarefas mais mecânicas deste
processo \cite{assemblers}. As tarefas mais importantes são a codificação de
instruções e o cálculo dos endereços de salto. 

A codificação de instruções, no contexto do código RISCO, é a funcionalidade que
traduz uma descrição textual de uma instrução RISCO (\S\ref{s:risco_instrucoes})
em uma palavra de 32 bits que seja reconhecida pelo processador. Já o cálculo
dos endereços de salto é uma análise que determina todas as constantes
utilizadas em instruções de salto, sejam elas um \texttt{jmp} ou \texttt{sr}.
Isto se dá através do uso de rótulos na linguagem de montagem.

\begin{algorithm}[htp]
\begin{center}
\begin{verbatim}

     ... # conjunto A
   label1:
     add $r1, $r2, $r3
     sub $r4, $r0, $r4
     jmp label2
     ... # conjunto B
   label2:
     add! $r0, $r1, $r2
     jmpeq label1
\end{verbatim}
\end{center}
\caption{Exemplo do uso de rótulos na linguagem de montagem
\label{alg:exemplo_rotulos}}
\end{algorithm}

Considere o exemplo \ref{alg:exemplo_rotulos}, na sintaxe do \texttt{risco-as}.
Os rótulos \texttt{label1} e \texttt{label2} são constantes inteiras que
representam a posição das instruções que os seguem de imediato. Desta maneira,
eles podem ser usados como operandos em instruções, como no exemplo acima.
Entretanto, o valor destas duas constantes não é aparente. Ele depende do número
de instruções nos conjuntos A e B (omitidos por clareza). Qualquer reorganização
do código nestes conjuntos, ou nas instruções mostradas acima, iria mudar estes
valores. Este cálculo é uma tarefa tediosa, porém perfeitamente dentro das
possibilidades de análise de um montador.

A seguir será analisada em detalhes a linguagem de montagem utilizada pelo
montador do RISCO.

\subsection{Linguagem de montagem do RISCO}
\label{ss:assembly_risco}

A especificação original do RISCO é acompanhada por um trabalho
\cite{risco_montador} que descreve uma linguagem de montagem para este
processador, porém não foi possível conseguir uma cópia deste software. Desta
maneira, foi decidido que uma nova linguagem de montagem seria definida para o
RISCO, implementada pelo \texttt{risco-as}.

A linguagem foi modelada tendo como base a gramática do montador/simulador Spim
\cite{spim}. Não foi utilizada a linguagem original do primeiro montador do
RISCO pois esta apresenta uma sintaxe que difere bastante das linguagens em uso
atualmente, com relação às diretivas e a definição de macros. Ao mesmo tempo,
foi aproveitada esta oportunidade para incluir certas funcionalidades que são
assumidas pelo módulo de geração de código do LLVM. 

Para facilitar a sua implementação, as funcionalidades de definição de
constantes internas e macros foi delegada ao pré-processador C \cite{c}, que é
executado antes que o arquivo fonte seja entregue ao \texttt{risco-as}. Desta
maneira, é possível utilizar a sintaxe já conhecida por programadores C para
definir macros textuais em um arquivo da linguagem de montagem.

O restante do montador foi dividido em 4 módulos simples: analisador léxico,
analisador sintático, analisador semântico e o gerador de código. Os
analisadores léxico e sintático foram desenvolvidos utilizando-se as ferramentas
livres \textbf{Flex} e \textbf{Bison} \cite{flex_bison}.

O Flex é um gerador de analisadores léxicos baseados em autômatos. Ele lê uma
descrição dos lexemas da linguagem em forma de expressões regulares e gera o
analisador léxico. Já o Bison é um gerador de analisadores sintáticos. Ele
recebe como entrada uma gramática LALR(1) anotada com ações, trechos de código
em C que são executados quando uma regra da gramática é reconhecida, e gera um
programa C capaz de realizar a análise sintática a partir dos tokens gerados
pelo produto do Flex.

\subsubsection*{Elementos léxicos}

O analisador léxico reconhece os seguintes elementos:

\begin{itemize}
  \item Comentários em uma única linha, iniciados pelo caractere ``\#''. Os
  símbolos de pontuação utilizados são: \texttt{`.', `:', `,', `+', `[', `]',
  `;', `!'} e \texttt{`@'}.
  
  \item Identificadores de diretiva, tais como: \texttt{.word}, \texttt{.ascii},
  \texttt{.resw}, \texttt{.text} e \texttt{.global}. Também reconhece
  identificadores de instruções, utilizando a nomenclatura do apêndice
  \ref{c:apendice_instrucoes}. Exemplos: \texttt{add}, \texttt{xor} e
  \texttt{sll}.
  
  \item Identificadores de registradores, da forma: \texttt{[\%|\$][rR][0-9]+}.
  Também reconhece apelidos de registradores utilizados pelo compilador, tais
  como: \texttt{\$pc}, \texttt{\$psw} e \texttt{\$sp}.
  
  \item Identificadores alfanuméricos que não iniciem com um dígito, strings
  literais cercadas por aspas duplas e constantes numéricas em decimal e
  hexadecimal.
  
  \item Todos os espaços em branco entre os lexemas são ignorados. 
\end{itemize}

\subsubsection*{Gramática e Semântica da linguagem}
\label{ss:gramatica_semantica_assembly}

A gramática da linguagem\footnote{Para simplificar o texto, apresentamos uma
versão reduzida da gramática original escrita na sintaxe do Bison. Entretanto,
não há mudanças significativas com relação a original} de
montagem será apresentada utilizando a notação BNF \cite{algol_report}
estendida. Os símbolos entre \texttt{``<''} e \texttt{``>''} são não terminais.
Todos os outros são representações de tokens. Os símbolos entre aspas duplas
indicam o próprio valor do token. O símbolo \texttt{``\#''} indica a produção
vazia.

\begin{verbatim}
  <programa>    ::= <declaracoes> <secoes>
  <declaracoes> ::= <declaracoes> ".start"  t_identifier | 
                    <declaracoes> ".global" t_identifier |
                    <declaracoes> ".extern" t_identifier | #
  <secoes>      ::= <secoes> <dados> | <secoes> <codigo> | #
\end{verbatim}

Um programa é definido como uma sequência de \emph{declarações} e uma sequência
de \emph{seções}. Uma declaração serve para indicar 3 casos: se um símbolo é
visível externamente em outra unidade de compilação (\texttt{.global}), se ele
pertence a outra unidade (\texttt{.extern}) ou se ele será o ponto de início do
programa (\texttt{.start}). Após as declarações, seguem as especificações de
seções. O binário final irá conter somente duas seções, uma de dados e outra de
código executável. Entretanto, o texto poderá conter fragmentos delas
separadamente.

\begin{verbatim}
  <dados> ::= ".data" <diretivas>
  <diretivas> ::= <diretivas> ".ascii" t_string_literal |
                  <diretivas> ".word" t_integer |
                  <diretivas> ".byte" t_integer |
                  <diretivas> ".resw" t_integer |
                  <diretivas> ".resb" t_integer | #
\end{verbatim}

A seção de dados é utilizada para o armazenamento estático de variáveis
utilizadas pelo programa. É, por exemplo, a região de armazenamento utilizada
para as variáveis globais em um programa C. As diretivas \texttt{.ascii},
\texttt{.word} e \texttt{.byte} reservam o espaço de cada tipo e já iniciam o
seu valor com o argumento dado. As diretivas \texttt{.resw} e \texttt{.resb} só
reservam a quantidade de variáveis indicada, inicialmente com valor 0.

\begin{verbatim}
  <codigo> ::= ".text" <instrucoes>
  <instrucoes> ::= <instrucoes> <rotulos> <instrucao> [";"] | #
  <instrucao> ::= <aritmetica_logica> ["!"] <operandos_normais> |
                  <salto>             ["!"] <operandos_salto>   |
                  <chamada_rotina>    ["!"] <operandos_salto>   |
                  <leitura_memoria>   ["!"] <operandos_leitura> |
                  <escrita_memoria>   ["!"] <operandos_escrita>
  <rotulos> ::= <rotulos> t_identifier ":" | #
\end{verbatim}

A seção de código consiste de uma lista de instruções. Cada uma pode ser
precedida por $n$ rótulos e, caso o seu mnemônico seja seguido pelo caractere
\texttt{``!''}, o seu bit APS (\ref{s:risco_instrucoes}) será 1. Os elementos
não terminais correspondentes aos tipos de instrução equivalem aos tokens dos
opcodes de cada classe. Dependendo do tipo da instrução, há uma sintaxe
diferenciada para a especificação dos seus operandos.

\begin{verbatim}
  <operandos_normais> ::= t_register "," t_register "," t_register
                        | t_register "," t_register "," <constante>
                        | t_register "," <constante_estendida>
  <operandos_salto> ::= t_register | <constante> | <operandos_normais>
  <operandos_leitura> ::=
      t_register "," "[" <constante> ["+" t_register] "]"
    | t_register "," "[" t_register  ["+" (t_register | <constante>)] "]"
  <operandos_escrita> ::=
      "[" <constante> ["+" t_register] "]" "," t_register
    | "[" t_register  ["+" (t_register | <constante>)] "]" "," t_register
\end{verbatim}

A regra para operandos normais equivale aos 3 formatos do campo de operandos,
discutido anteriormente. A distinção entre as 5 interpretações se dá analisando
quais registradores foram escolhidos. Para as operações de salto, é possível
especificar somente o destino do salto, e o montador se encarrega de utilizar o
registrador 31 e 0 quando necessários. Para operações de leitura e escrita na
memória, a sintaxe tradicional com colchetes é utilizada. 

\begin{verbatim}
  <constante> ::= t_integer | t_identifier
  <constante_estendida> ::= ["@"] <constante>
\end{verbatim}

As constantes podem ser inteiros ou rótulos. Em ambos os casos, caso o
caractere \texttt{``@''} preceda a constante, o formato da instrução será o 4
(a constante é carregada nos bits mais significativos do operando).

\begin{algorithm}[ht!]
\caption{Exemplo de programa na linguagem de montagem RISCO}
\label{alg:exemplo_assembly}
\begin{verbatim}

#include "risco/stdlib.h"
#define cmp(a, b) add! $zero, a, b
#define nop       add $zero, $zero, $zero

.global main

.data
str: .ascii "Hello World!" .byte 0

.text
main:
        add $t1, $zero, $zero    # index
        add $a0, $zero, $zero    # counter
loop:
        ldpoi $t2, [str + $t1]
        cmp ($t2, 0)
        jmpeq out
        nop
        add $a0, $a0, 1
        jmp loop
        nop
out:
        sr print_int
        nop
        add $a0, $zero, $zero
        sr exit
        nop
\end{verbatim}
\end{algorithm}

O programa \ref{alg:exemplo_assembly} é um exemplo completo de código na
linguagem de montagem do RISCO. Ele define uma string na área de dados
(terminada com um byte nulo) do código, e quando for executado conta o tamanho
da string e o imprime na saída padrão. O código faz uso da biblioteca padrão do
RISCO e de funcionalidades do \texttt{risco-sim} que serão mencionadas
posteriormente.

Observando o código deste exemplo é possível destacar algumas das
funcionalidades do montador que já foram mencionadas. O código passa pelo
pré-processador C antes de ser lido pelo \texttt{risco-as}. Desta maneira, foi
possível definir os dois macros de  instruções e incluir um arquivo externo.
Além disso, o uso dos rótulos facilitou a codificação do exemplo. Não é preciso
se preocupar com os endereços reais das instruções. 

Para calcular os valores dos rótulos, o montador realiza um processo de 2 passos
sobre o código fonte. Primeiramente, uma tabela de símbolos é criada, mapeando
símbolos para valores inteiros, inicialmente vazia. A medida que o programa
percorre o código fonte pela primeira vez, ele mantêm um contador indicando
quantos bytes já foram observados, em termos de quantidade de instruções. Dessa
maneira, ao encontrar uma definição de rótulo ele pode marcar na tabela qual o
seu valor, que é igual a posição da próxima instrução no texto. Este processo
deve levar em conta as diretivas de dados, introduzidas na próxima seção. Ao
percorrer o código fonte pela segunda vez, ao encontrar uma instrução que
utilize um rótulo como operando, o rótulo é substituído pelo seu valor na
tabela. 

O programador também não se preocupa com os 5 formatos de instruções de 
operandos discutidos no capítulo \ref{c:risco}. Tomando como exemplo a instrução
de leitura da memória, \texttt{ldpoi}. Foi possível escrevê-la em uma notação
familiar, sem atentar para a definição de DST, FT1 e FT2. Dependendo dos tipos e
da ordem dos argumentos definidos para uma  instrução, o montador deduz qual
será a instrução de máquina equivalente. Estas funcionalidades também
facilitaram a implementação do compilador.

\subsection{Funcionalidade do ligador}

No exemplo \ref{alg:exemplo_assembly} é possível observar que o código fez uso
de subrotinas que não foram definidas neste arquivo: \texttt{print\_int} e
\texttt{exit}. O código fonte destas duas rotinas, em linguagem de montagem,
está em outro arquivo. O segundo arquivo contêm diretivas \texttt{.global} para
esses dois símbolos, de modo que eles sejam visíveis externamente. Além disso, o
arquivo \texttt{risco$/$stdlib.h}, incluído pelo código do exemplo, contêm
diretivas \texttt{.extern} para os símbolos.

O software denominado de \emph{ligador} é comumente responsável por agregar
todas as unidades de compilação de um programa, identificar símbolos externos,
símbolos locais e dependências entre as unidades para então gerar um único
arquivo binário com todo o código, como no modelo da figura
\ref{fig:fluxo_desenvolvimento}. Uma das decisões de projeto para o
\texttt{risco-as} foi integrar a funcionalidade de ligador nesta ferramenta.
Esta direção fez com que a complexidade do montador aumentasse, porém é um
risco aceitável quando comparado aos esforços necessários para desenvolver e
manter o ligador.

Foi estudada a opção de utilizar um formato de código binário relocável
existente, como o ELF para sistemas Linux. Algumas das vantagens seriam
\cite{elf_linux}: não precisaria definir outro formato; pode-se utilizar o
conjunto de ferramentas já disponíveis que trabalham com o ELF, inclusive o
ligador \texttt{ld}; permite manipulação de alta performance; é um formato
flexível e extensível. Optou-se por seguir com a implementação do ligador
embutido no montador após serem analisados os requisitos da plataforma de
desenvolvimento para o RISCO e ser percebido que portabilidade e alta
performance ainda não são prioridades. O que era necessário era agilidade na
implementação desta peça básica, a fim de que o estudo e desenvolvimento das
ferramentas para linguagens de alto nível pudesse ser iniciado.

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.7]{images/ligador-uniao}
  \textsf{\caption{Processo de união de unidades de compilação no
          \texttt{risco-as} \label{fig:ligador_uniao}}}
\end{figure}

A resolução de símbolos é feita através de um esquema simples, baseado no
modelo de cálculo dos valores dos rótulos apresentado na sessão
\ref{ss:gramatica_semantica_assembly}. O código que resulta da ligação das
diferentes unidades de compilação pode ser visto como a união do código de
todas, fazendo a reescrita dos seus rótulos, como na figura
\ref{fig:ligador_uniao}. Com o arquivo resultante desta união, pode-se utilizar
o esquema de resolução de rótulos discutido anteriormente, que trabalha em um
único arquivo. Na prática, este é um esquema ineficiente pois pode gerar um
arquivo de tamanho excessivo. Por este motivo, os rótulos globais são mantidos
em uma tabela de símbolos globais, separadamente das tabelas locais de cada
arquivo. A união das unidades de compilação nunca é feita explicitamente.


\section{Simulador}

O montador \texttt{risco-as} gera um arquivo binário puro contendo a
codificação exata das instruções descritas no programa em linguagem de
montagem. As instruções contidas neste arquivo não correspondem ao conjunto de
operações definidas pelo computador \emph{host}, onde ocorre o desenvolvimento
do software. O desenvolvedor necessita de um dispositivo que execute fielmente
as instruções contidas no executável, e que possa informá-lo do comportamento
apresentado pelo programa. O dispositivo que representa o sistema embarcado
contendo o processador RISCO pode assumir basicamente 3 formas distintas:

\begin{itemize}
\item \textit{Dispositivo real}: o código é executado em um equipamento físico
real, um SE baseado em processador RISCO. Neste caso, o carregador é um software
capaz de se comunicar com o dispositivo externo e carregar o código em sua
memória. Como exemplo disto, pode-se citar um FPGA programado para
simular um processador RISCO.

\item \textit{Especificação executável}: uma técnica comum para prototipagem
rápida de sistemas é utilizar uma linguagem de especificação de hardware que
seja executável, possibilitando que um software especializado realize uma
simulação de alta fidelidade. Neste caso, o carregador é um módulo particular
deste software, responsável por incluir o código executável na representação
interna da memória do circuito. Um exemplo desta forma são ferramentas de
simulação VHDL.

\item \textit{Simulador artificial}: neste caso, o dispositivo é representado
por um software, escrito em uma linguagem de programação de alto nível,
responsável por ler um arquivo binário executável de entrada e executar suas
instruções uma a uma, de modo que os efeitos colaterais possam ser observados na
máquina hospedeira (\emph{host}).
\end{itemize}

O trabalho inicial em cima do RISCO \cite{risco_tese} envolveu a sua
sintetização em um circuito integrado, logo seria lógico considerar a primeira
possibilidade de execução do código. Porém, esta alternativa é pouco prática
pois o processo de carregamento do código na memória do dispositivo não é
trivial, e isto desacelera o desenvolvimento de software para a plataforma
consideravelmente.

A utilização de uma especificação executável é uma opção válida, tendo em vista
que haviam modelos do RISCO em SystemC e VHDL disponíveis. Porém estes
modelos não tem como objetivo suportar o desenvolvimento de software para o
processador, e sim validar a especificação do processador em si. 

Desta forma, desenvolvemos um simulador artificial que implementa a arquitetura
do RISCO com fidelidade. Existem diversas vantagens para essa abordagem. Em
geral, simuladores deste tipo apresentam performance superior aos outros. Isto
decorre do fato de que esse simulador tem o privilégio de ser executado na
máquina de desenvolvimento do código, que comumente tem uma performance muito
superior a do sistema embarcado. Neste caso, o carregador é simplesmente um
módulo interno do simulador que lê o arquivo binário proveniente do montador. 

Além disso, como visto no capítulo \ref{c:sistemas_embarcados}, o programador
deve contar com um ambiente que suporte simulações rápidas da execução de um
programa, e mesmo assim possa obter resultados iguais ou comparáveis aos
resultados obtidos quando o código é executado em um dispositivo real. 

Com relação a utilização de simuladores artificiais para plataformas RISC, cabe
mencionar como exemplo a linha de processadores MIPS, que é amplamente utilizada
para o ensino de arquitetura e organização de computadores \cite{webmips}, assim
como em sistemas embarcados \cite{mips_embedded}. Existem diversos simuladores
para este processador, tais como o apresentado em \cite{mars} e o Spim
\cite{spim}.
  
O simulador em si foi desenvolvido como um interpretador simples que considera
o conjunto de instruções do RISCO como \emph{bytecodes}, e age como uma máquina
virtual. É um padrão de projeto bastante conhecido, tendo como exemplo
destacado de uso a máquina virtual da plataforma Java \cite{jvm}. Uma
simplificação do loop de interpretação está presente no exemplo
\ref{alg:loop_simulador}

\begin{algorithm}[t!]
\caption{Loop de interpretação do \texttt{risco-sim}, simplificado}
\label{alg:loop_simulador}
\begin{verbatim}

word reg[NUM_REGISTERS]
byte memory[MEMORY_SIZE];

struct Decoded {
  unsigned opcode;
  bool aps;
  int operand_format;
  ...
};

decode(unsigned instruction, Decoded& decoded) {
  decoded.opcode = instruction >> 25;
  decoded.aps = instruction & (1 << 24);
  int f1_f0 = (instruction >> 22) & 0x03;
  ...
}

void run() {
  reg[PC_REG] = start_position;
  reg[SP_REG] = MEMORY_SIZE-1;

  while (running) {
    unsigned instr = memory_read(reg[PC_REG]);
    reg[PC_REG] += 4;
    Decoded decoded = decode(instr);
    switch (decoded.opcode) {
      case OP_ADD:
        reg[decoded.dst] = decoded.ft1 + decoded.ft2;
        break;
      ...
    }
    if (decoded.aps) update_psw();
  }
}
\end{verbatim}
\end{algorithm}

\abrv[SP -- Stack Pointer]

Uma instrução é lida como um inteiro sem sinal. Para realizar a sua
interpretação e execução, a função \texttt{decode} decodifica a
palavra e separa os seus campos relevantes. A rotina \texttt{run} apresenta o
corpo do loop em si, onde cada instrução é lida da memória, decodificada e
executada. Note que o simulador inicia o contador de programa (PC) e o ponteiro
da pilha (SP) automaticamente, entre outras coisas. Iremos abordar o
registrador SP mais adiante.


\subsection{Formato do executável}

Para que as ferramentas \texttt{risco-as} e \texttt{risco-sim} consigam
trabalhar juntas, o arquivo binário gerado pelo montador precisa seguir um
certo formato pré-combinado entre os dois softwares. Este formato é denominado
formato de arquivo executável, ou formato de interface binária entre aplicações
\cite{linkers_loaders}. Como o ambiente de desenvolvimento para o RISCO não
suporta o uso de compilação separada ou bibliotecas dinâmicas, tal formato pode
ser mais simples, contendo somente duas seções: dados e instruções. O formato
binário é detalhado na figura \ref{fig:formato_executavel}

\begin{figure}[htb]
  \centering
  \includegraphics[scale=0.85]{images/formato-executavel}
  \textsf{\caption{Formato de arquivo executável na plataforma RISCO
          \label{fig:formato_executavel}}}
\end{figure}

O arquivo inicia com dois números inteiros de 4 bytes cada. Eles são
codificados com os bytes menos significativos no início do arquivo (codificação
\emph{little-endian}). O primeiro aponta para uma posição dentro do segmento de
texto onde fica o símbolo de início de programa, definido no código em
linguagem de montagem com a diretiva \texttt{.start}. O segundo número é o
deslocamento necessário para partir do início do arquivo até o início da
seção de dados. Este valor não é utilizado atualmente no simulador.

A vantagem mais significativa em utilizar um formato de executável simples como
o apresentado acima é que o carregador do programa não precisa realizar nenhum
pré-processamento no arquivo. Após ler os dois números do início, ele pode
mapear o resto do arquivo na memória e começar a executar as instruções. Não é
preciso mover as seções de texto e de dados das suas posições originais. 


\subsection{Chamadas de sistema}
\label{ss:risco_sim_syscalls}

Durante a execução de um código RISCO, o simulador é capaz de exibir
informações de depuração, tais como os valores de todos os registradores, ou o
valor de alguma posição de memória. Além disso, é possível interromper a
execução do programa e continuar de certo ponto. Entretanto, este tipo de
interação com o código, onde é necessário examinar os valores dos
registradores manualmente, requer mais esforço do programador para entender o
comportamento apresentado pelo programa. Utilizando somente as instruções
descritas no apêndice \ref{c:apendice_instrucoes}, o código não tem os meios
para interagir com a plataforma onde executa. As únicas operações que podem ser
feitas são manipulações com os valores da memória e dos registradores.

Devido a estes problemas, introduzimos a utilização de \emph{chamadas de
sistema} no \texttt{risco-sim}. Desta maneira, um código em linguagem de
montagem pode requisitar uma certa funcionalidade da plataforma base, que
poderá executar operações de interação com o usuário já que o simulador é um
programa normal no sistema operacional host.

Para realizar uma chamada de sistema, o programa deve colocar o código da
chamada no registrador \texttt{\$A0} (R03), e os respectivos parâmetros, quando
necessários, nos registradores \texttt{\$A1} (R04) a \texttt{\$A4} (R07). Depois
da preparação destes registradores, é necessário invocar a plataforma base
utilizando a instrução \texttt{syscall}. Após esta instrução, o registrador
\texttt{\$V0} (R02) irá conter o seu valor de retorno, caso ele exista.
Esta instrução não pertence ao conjunto original do RISCO, ela só é
reconhecida pelo \texttt{risco-sim}. Para o seu opcode, utilizamos um dos
códigos não utilizados das instruções do tipo aritmético-lógico
(\S\ref{s:risco_instrucoes}).

\begin{table}[htb!]
\begin{center}
\begin{tabular}{ c | c | c | c | c }
  \textbf{Nome} & \textbf{Código} & \textbf{Argumentos} & \textbf{Retorno} &
  \textbf{Equivalente em C} \\
  \hline
  
  \texttt{print\_int} & 1 & \texttt{int i} & & \texttt{printf(``\%d'', i)} \\
  
  \texttt{print\_uint} & 2 & \texttt{unsigned int i} & &
  \texttt{printf(``\%u'', i)} \\
  
  \texttt{print\_char} & 3 & \texttt{char c} & & \texttt{printf(``\%c'', c)} \\
  
  \texttt{print\_string} & 4 & \texttt{char* s} & & \texttt{puts(s)} \\
  
  \texttt{read\_int} & 5 & & \texttt{int i} & \texttt{scanf(``\%d'', \&i)} \\
  
  \texttt{read\_char} & 6 & & \texttt{char c} & \texttt{scanf(``\%c'', \&c)} \\
  
  \texttt{read\_string} & 7 & \texttt{char* s; int n} & &
  \texttt{fgets(s,n,STDIN)} \\
  
  \texttt{fopen} & 8 & \texttt{char* f, m} & \texttt{int fd} &
  \texttt{fopen(f,m)} \\
  
  \texttt{fwrite} & 9 & \texttt{char* b; int n, fd} & \texttt{int k} &
  \texttt{fwrite(b,1,n,fd)} \\
  
  \texttt{fread} & 10 & \texttt{char* b; int n, fd} & \texttt{int k} &
  \texttt{fread(b,1,n,fd)} \\
  
  \texttt{fclose} & 11 & \texttt{int fd} & \texttt{int st} &
  \texttt{fclose(fd)} \\
  
  \texttt{malloc} & 12 & \texttt{int n} & \texttt{void* ptr} & 
  \texttt{malloc(n)} \\
  
  \texttt{free} & 13 & \texttt{void* ptr} & & \texttt{free(ptr)} \\
  
  \texttt{exit} & 99 & \texttt{int code} & & \texttt{exit(code)} \\
  
\end{tabular}
\end{center}
\caption{Chamadas de sistema do \texttt{risco-sim}
         \label{tab:chamadas_sistema}}
\end{table}

Na tabela \ref{tab:chamadas_sistema} apresentamos o conjunto de chamadas de
sistema implementado, junto com os seus identificadores. A semântica da operação
é dada por um trecho de código C cujo efeito é igual ao da chamada. Incluímos
chamadas para leitura e impressão de valores simples na entrada e saída padrão,
respectivamente. Como veremos no capítulo \ref{c:risco_llvm}, estas chamadas,
junto com as chamadas \texttt{malloc} e \texttt{free}, foram essenciais para
facilitar a verificação do compilador RISCO. As rotinas de manipulação de
arquivos também são úteis neste contexto.

Em um código C em ambiente Unix, as chamadas de sistema tem um funcionamento
semelhante ao apresentado acima. Elas seguem a especificação POSIX
\cite{linux_programming_interface}, com algumas extensões. Na prática, os
códigos no espaço de usuário (fora do espaço do kernel) não utilizam estas
chamadas diretamente. A biblioteca padrão C inclui funções que encapsulam o ato
de invocar a chamada de sistema com uma função normal, que pode ser invocada
utilizando a convenção de chamada do sistema em questão. Por exemplo, o
código da função \texttt{printf}, parte da biblioteca padrão, é o responsável
por realizar a chamada de sistema com uma instrução parecida com a
\texttt{syscall}.

Adotamos este esquema de funções \emph{proxy} nas chamadas de sistema do RISCO.
Como visto no exemplo \ref{alg:exemplo_assembly}, o código fez uma chamada de
subrotina normal para \texttt{print\_int}. Esta função é responsável por
carregar o código correto da chamada de sistema (neste caso, 1) e executar a
instrução \texttt{syscall}. Existe uma função proxy para cada chamada de
sistema apresentada na tabela \ref{tab:chamadas_sistema}, com os nomes da
coluna ``Nome''.

Este capítulo conclui a apresentação das ferramentas que compõem a plataforma
base de desenvolvimento para o processador RISCO. Nos próximos capítulos será
analisado o suporte a linguagens de alto nível. Inicialmente é feita uma
exposição do projeto LLVM e da sua significância para este trabalho. Em seguida,
as ferramentas \texttt{risco-llvm} e \texttt{risco-cfg} são discutidas.
